package frame.project;

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.net.Uri;
import android.widget.ImageView;
import android.widget.Toast;

public class ImageProcess extends Activity {

	// keep track of cropping intent
	final int PIC_CROP = 2;
	// captured picture uri
	private Uri picUri;
	ImageView imageView;

	public final static double PI = 3.14159d;
	public final double FULL_CIRCLE_DEGREE = 360d;
	public final static double HALF_CIRCLE_DEGREE = 180d;
	public final static double RANGE = 256d;

	public void performCrop() {
		// take care of exceptions
		try {
			// call the standard crop action intent (the user device may not
			// support it)
			Intent cropIntent = new Intent("com.android.camera.action.CROP");
			// indicate image type and Uri
			cropIntent.setDataAndType(picUri, "image/*");
			// set crop properties
			cropIntent.putExtra("crop", "true");
			// indicate aspect of desired crop
			cropIntent.putExtra("aspectX", 1);
			cropIntent.putExtra("aspectY", 1);
			// indicate output X and Y
			cropIntent.putExtra("outputX", 256);
			cropIntent.putExtra("outputY", 256);
			// retrieve data on return
			cropIntent.putExtra("return-data", true);
			// start the activity - we handle returning in onActivityResult
			startActivityForResult(cropIntent, PIC_CROP);
		}
		// respond to users whose devices do not support the crop action
		catch (ActivityNotFoundException anfe) {
			// display an error message
			String errorMessage = "Whoops - your device doesn't support the crop action!";
			Toast toast = Toast
					.makeText(this, errorMessage, Toast.LENGTH_SHORT);
			toast.show();
		}
	}

	/**
	 * Do a rotation on Bitmap
	 * 
	 * @param bMap
	 * @param rotate
	 * @author Jourdan
	 */
	public Bitmap performRotate(Bitmap bMap) {
		// Create object of new Matrix
		Matrix matrix = new Matrix();

		// Rotate the matrix into 90 degree
		matrix.postRotate(90);

		// Create bitmap with new values.
		Bitmap bMapRotate = Bitmap.createBitmap(bMap, 0, 0, bMap.getWidth(), bMap.getHeight(), matrix, true);
		
		// Return into bMapRotate
		return bMapRotate;
	}

	/**
	 * Do a blur effect on Bitmap
	 * 
	 * @param src
	 * @param blurValue
	 * @author Jourdan
	 */
	public Bitmap performBlur(Bitmap src, int blurValue) {
		// Get width and height from the original source
		int width = src.getWidth();
		int height = src.getHeight();

		
		BlurMaskFilter blurMaskFilter;
		// Create object of new Paint
		Paint paintBlur = new Paint();

		Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
		Canvas canvas = new Canvas(bitmap);

		// Create background in White
		Bitmap alpha = src.extractAlpha();
		paintBlur.setColor(0xFFFFFFFF);
		canvas.drawBitmap(alpha, 0, 0, paintBlur);

		// Create outer blur, in White
		blurMaskFilter = new BlurMaskFilter(blurValue, BlurMaskFilter.Blur.OUTER);
		paintBlur.setMaskFilter(blurMaskFilter);
		canvas.drawBitmap(alpha, 0, 0, paintBlur);

		// Create inner blur
		blurMaskFilter = new BlurMaskFilter(blurValue, BlurMaskFilter.Blur.INNER);
		paintBlur.setMaskFilter(blurMaskFilter);
		canvas.drawBitmap(src, 0, 0, paintBlur);

		// Return final bitmap
		return bitmap;
	}

	/**
	 * Do a Greyscale effect on Bitmap
	 * 
	 * @param src
	 * @author Jourdan
	 */
	public Bitmap doGreyscale(Bitmap src) {
		// Constant factors
		final double GS_RED = 0.299;
		final double GS_GREEN = 0.587;
		final double GS_BLUE = 0.114;
		// Create output bitmap
		Bitmap bitmap = Bitmap.createBitmap(src.getWidth(), src.getHeight(), src.getConfig());
		// Pixel information
		int A, R, G, B;
		int pixel;

		// Get width and height from the original source
		int width = src.getWidth();
		int height = src.getHeight();

		// Scan through every single pixel
		for (int x = 0; x < width; ++x) {
			for (int y = 0; y < height; ++y) {
				// Get one pixel color
				pixel = src.getPixel(x, y);
				// Retrieve color of all channels
				A = Color.alpha(pixel);
				R = Color.red(pixel);
				G = Color.green(pixel);
				B = Color.blue(pixel);
				// Take conversion up to one single value
				R = G = B = (int) (GS_RED * R + GS_GREEN * G + GS_BLUE * B);
				// Set new pixel color to output bitmap
				bitmap.setPixel(x, y, Color.argb(A, R, G, B));
			}
		}
		// Return final bitmap
		return bitmap;
	}

	/**
	 * Do an Invert effect on Bitmap
	 * 
	 * @param src
	 * @author Jourdan
	 */
	public Bitmap doInvert(Bitmap src) {
		// Create new bitmap with the same settings as source bitmap
		Bitmap bitmap = Bitmap.createBitmap(src.getWidth(), src.getHeight(), src.getConfig());
		// Color info
		int A, R, G, B;
		int pixelColor;
		// Get width and height from the original source
		int height = src.getHeight();
		int width = src.getWidth();

		// Scan through every pixel
		for (int y = 0; y < height; y++) {
			for (int x = 0; x < width; x++) {
				// Get one pixel
				pixelColor = src.getPixel(x, y);
				// Saving alpha channel
				A = Color.alpha(pixelColor);
				// Inverting byte for each R/G/B channel
				R = 255 - Color.red(pixelColor);
				G = 255 - Color.green(pixelColor);
				B = 255 - Color.blue(pixelColor);
				// set newly-inverted pixel to output image
				bitmap.setPixel(x, y, Color.argb(A, R, G, B));
			}
		}
		// Return final bitmap
		return bitmap;
	}

	/**
	 * Do a Sepia effect on Bitmap
	 * 
	 * @param src
	 * @param depth
	 * @param red
	 * @param green
	 * @param blue
	 * @author Jourdan
	 */
	public Bitmap doSepia(Bitmap src, int depth, double red, double green, double blue) {
		// Get width and height from the original source
		int width = src.getWidth();
		int height = src.getHeight();
		// Create output bitmap
		Bitmap bitmap = Bitmap.createBitmap(width, height, src.getConfig());
		// constant Grayscale
		final double GS_RED = 0.3;
		final double GS_GREEN = 0.59;
		final double GS_BLUE = 0.11;
		// Color information
		int A, R, G, B;
		int pixel;

		// Scan through all pixels
		for (int x = 0; x < width; ++x) {
			for (int y = 0; y < height; ++y) {
				// Get pixel color
				pixel = src.getPixel(x, y);
				// Get color on each channel
				A = Color.alpha(pixel);
				R = Color.red(pixel);
				G = Color.green(pixel);
				B = Color.blue(pixel);
				// Apply grayscale sample
				B = G = R = (int) (GS_RED * R + GS_GREEN * G + GS_BLUE * B);

				// Apply intensity level for sepid-toning on each channel
				R += (depth * red);
				if (R > 255) {
					R = 255;
				}

				G += (depth * green);
				if (G > 255) {
					G = 255;
				}

				B += (depth * blue);
				if (B > 255) {
					B = 255;
				}

				// Set new pixel color to output image
				bitmap.setPixel(x, y, Color.argb(A, R, G, B));
			}
		}
		// Return final bitmap
		return bitmap;
	}

	/**
	 * Do a Bright effect on Bitmap
	 * 
	 * @param src
	 * @param value
	 * @author Jourdan
	 */
	public Bitmap doBright(Bitmap src, int value) {
		// Get width and height from the original source
		int width = src.getWidth();
		int height = src.getHeight();
		// Create output bitmap
		Bitmap bitmap = Bitmap.createBitmap(width, height, src.getConfig());
		// Color information
		int A, R, G, B;
		int pixel;

		// Scan through all pixels
		for (int x = 0; x < width; ++x) {
			for (int y = 0; y < height; ++y) {
				// Get pixel color
				pixel = src.getPixel(x, y);
				A = Color.alpha(pixel);
				R = Color.red(pixel);
				G = Color.green(pixel);
				B = Color.blue(pixel);

				// Increase/decrease each channel
				R += value;
				if (R > 255) {
					R = 255;
				} else if (R < 0) {
					R = 0;
				}

				G += value;
				if (G > 255) {
					G = 255;
				} else if (G < 0) {
					G = 0;
				}

				B += value;
				if (B > 255) {
					B = 255;
				} else if (B < 0) {
					B = 0;
				}

				// Apply new pixel color to output bitmap
				bitmap.setPixel(x, y, Color.argb(A, R, G, B));
			}
		}
		// Return final bitmap
		return bitmap;
	}

	/**
	 * Do a Dark effect on Bitmap
	 * 
	 * @param src
	 * @param red
	 * @param green
	 * @param blue
	 * @author Jourdan
	 */
	public Bitmap doDark(Bitmap src, double red, double green, double blue) {
		// Create output image
		Bitmap bitmap = Bitmap.createBitmap(src.getWidth(), src.getHeight(), src.getConfig());
		// Get width and height from the original source
		int width = src.getWidth();
		int height = src.getHeight();
		// Color information
		int A, R, G, B;
		int pixel;
		// Constant value curve
		final int MAX_SIZE = 256;
		final double MAX_VALUE_DBL = 255.0;
		final int MAX_VALUE_INT = 255;
		final double REVERSE = 1.0;

		// Gamma arrays
		int[] gammaR = new int[MAX_SIZE];
		int[] gammaG = new int[MAX_SIZE];
		int[] gammaB = new int[MAX_SIZE];

		// Setting values for every gamma channels
		for (int i = 0; i < MAX_SIZE; ++i) {
			gammaR[i] = (int) Math.min(MAX_VALUE_INT, (int)((MAX_VALUE_DBL * Math.pow(i / MAX_VALUE_DBL, REVERSE / red)) + 0.5));
			gammaG[i] = (int) Math.min(MAX_VALUE_INT, (int)((MAX_VALUE_DBL * Math.pow(i / MAX_VALUE_DBL, REVERSE / green)) + 0.5));
			gammaB[i] = (int) Math.min(MAX_VALUE_INT, (int)((MAX_VALUE_DBL * Math.pow(i / MAX_VALUE_DBL, REVERSE / blue)) + 0.5));
		}

		// Apply gamma table
		for (int x = 0; x < width; ++x) {
			for (int y = 0; y < height; ++y) {
				// Get pixel color
				pixel = src.getPixel(x, y);
				A = Color.alpha(pixel);
				// Look up gamma
				R = gammaR[Color.red(pixel)];
				G = gammaG[Color.green(pixel)];
				B = gammaB[Color.blue(pixel)];
				// Set new color to output bitmap
				bitmap.setPixel(x, y, Color.argb(A, R, G, B));
			}
		}

		// Return final bitmap
		return bitmap;
	}

	/**
	 * Do a Tint effect on Bitmap
	 * 
	 * @param src
	 * @param degree
	 * @author Jourdan
	 */
	public Bitmap doTint(Bitmap src, int degree) {
		// Get width and height from the original source
		int width = src.getWidth();
		int height = src.getHeight();
		// The array to receive bitmap pixels
		int[] pixel = new int[width * height];
		src.getPixels(pixel, 0, width, 0, 0, width, height);

		int RY, GY, BY, RYY, GYY, BYY, R, G, B, Y;
		double angle = (PI * (double) degree) / HALF_CIRCLE_DEGREE;

		int S = (int) (RANGE * Math.sin(angle));
		int C = (int) (RANGE * Math.cos(angle));

		for (int y = 0; y < height; y++)
			for (int x = 0; x < width; x++) {
				int index = y * width + x;
				int r = (pixel[index] >> 16) & 0xff;
				int g = (pixel[index] >> 8) & 0xff;
				int b = pixel[index] & 0xff;
				RY = (70 * r - 59 * g - 11 * b) / 100;
				GY = (-30 * r + 41 * g - 11 * b) / 100;
				BY = (-30 * r - 59 * g + 89 * b) / 100;
				Y = (30 * r + 59 * g + 11 * b) / 100;
				RYY = (S * BY + C * RY) / 256;
				BYY = (C * BY - S * RY) / 256;
				GYY = (-51 * RYY - 19 * BYY) / 100;
				R = Y + RYY;
				R = (R < 0) ? 0 : ((R > 255) ? 255 : R);
				G = Y + GYY;
				G = (G < 0) ? 0 : ((G > 255) ? 255 : G);
				B = Y + BYY;
				B = (B < 0) ? 0 : ((B > 255) ? 255 : B);
				pixel[index] = 0xff000000 | (R << 16) | (G << 8) | B;
			}
		
		// Create output image
		Bitmap bitmap = Bitmap.createBitmap(width, height, src.getConfig());
		bitmap.setPixels(pixel, 0, width, 0, 0, width, height);

		pixel = null;

		// Return final bitmap
		return bitmap;
	}
}
